package com.iplant.aps.serviceImpl.dao.aps;

import com.iplant.aps.service.po.aps.APSCapacityUsed;
import com.iplant.aps.service.po.aps.APSTaskPart;
import com.iplant.aps.service.po.aps.APSTaskPartPoint;
import com.iplant.aps.service.po.aps.APSTaskPartPointDay;
import com.iplant.aps.service.po.aps.dayPlan.APSTaskPartPointDayParent;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.enums.DBSchemas;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.basicenum.bfc.FMCShiftType;
import com.iplant.basic.service.po.bms.BMSEmployee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class APSTaskPartPointDayDAO extends BaseDAO {

    private static APSTaskPartPointDayDAO Instance = null;
    private static Logger logger = LoggerFactory.getLogger(APSTaskPartPointDayDAO.class);

    private APSTaskPartPointDayDAO() {
        super(APSTaskPartPointDay.class);
    }

    public static APSTaskPartPointDayDAO getInstance() {
        if (Instance == null)
            Instance = new APSTaskPartPointDayDAO();
        return Instance;
    }

    /**
     * 保存日计划
     */
    public void APS_SaveDayPlan(BMSEmployee wLoginUser, APSTaskPart wAPSTaskPart, APSTaskPartPoint wAPSTaskPartPoint,
                                OutResult<Integer> wErrorCode) {
        try {
            APSTaskPartPointDay wAPSTaskPartPointDay;
            List<APSCapacityUsed> wAPSCapacityUsedList;

            List<APSCapacityUsed> wShiftCapacityUsedList;

            for (String wDateStr : wAPSTaskPartPoint.PlanDayDetailNum.keySet()) {
                wAPSCapacityUsedList = wAPSTaskPartPoint.PlanDayDetailNum.get(wDateStr);

                for (FMCShiftType wFMCShiftType : FMCShiftType.values()) {
                    if (wFMCShiftType == FMCShiftType.Default) {
                        continue;
                    }

                    wShiftCapacityUsedList =
                            wAPSCapacityUsedList.stream().filter(p -> p.ShiftType == wFMCShiftType.getValue()).collect(Collectors.toList());

                    wAPSTaskPartPointDay = new APSTaskPartPointDay();
                    wAPSTaskPartPointDay.CreatorID = wLoginUser.ID;
                    wAPSTaskPartPointDay.EditorID = wLoginUser.ID;
                    wAPSTaskPartPointDay.OrderID = wAPSTaskPart.OrderID;
                    wAPSTaskPartPointDay.RoutePartID = wAPSTaskPart.RoutePartID;
                    wAPSTaskPartPointDay.RoutePartPointID = wAPSTaskPartPoint.RoutePartPointID;
                    wAPSTaskPartPointDay.TaskPartID = wAPSTaskPart.ID;
                    wAPSTaskPartPointDay.TaskPartPointID = wAPSTaskPartPoint.ID;
                    wAPSTaskPartPointDay.WorkShopID = wAPSTaskPart.WorkShopID;
                    wAPSTaskPartPointDay.WorkAreaID = wAPSTaskPart.WorkAreaID;
                    wAPSTaskPartPointDay.StationID = wAPSTaskPartPoint.StationID;

                    wAPSTaskPartPointDay.StationDate = StringUtils.parseCalendar(wDateStr, "yyyy-MM-dd");
                    wAPSTaskPartPointDay.ShiftType = wFMCShiftType.getValue();
                    wAPSTaskPartPointDay.PlantNum =
                            (float) wShiftCapacityUsedList.stream().mapToDouble(p -> p.UsedCapacity).sum();
                    wAPSTaskPartPointDay.SetCapacityMap =
                            wShiftCapacityUsedList.stream().collect(Collectors.toMap(p -> (p.EntityID + ""),
                                    p -> p.SetCapacity));
                    wAPSTaskPartPointDay.StationNumMap =
                            wShiftCapacityUsedList.stream().collect(Collectors.toMap(p -> (p.EntityID + ""),
                                    p -> p.UsedCapacity));
                    wAPSTaskPartPointDay.Active = 1;

                    this.UpdatePo(wLoginUser, wAPSTaskPartPointDay, wErrorCode);
                }
            }
        } catch (Exception ex) {
            logger.error("APS_SaveDayPlan", ex);
        }
    }


    public List<APSTaskPartPointDayParent> APS_QueryDayPlanParent(Calendar wDate,
                                                                  int wOrderID, String wRoutePartName,
                                                                  String wRoutePartPointName,
                                                                  Pagination wPagination,
                                                                  OutResult<Integer> wErrorCode) {
        List<APSTaskPartPointDayParent> wResult = new ArrayList<APSTaskPartPointDayParent>();
        try {
            String wSQL = StringUtils.Format("SELECT distinct t.OrderID,t3.Code OrderNo,t.RoutePartID,t" +
                            ".RoutePartPointID,t5.ActNum,t1.Name " +
                            "RoutePartName,t2.Name RoutePartPointName,t.TaskPartID,t4.Status TaskPartStatus,t" +
                            ".TaskPartPointID,t5.PlanNum,t1.OrderID RoutePartOrder,t2.OrderID RoutePartPointOrder " +
                            "FROM {0}.aps_task_partpoint_day t " +
                            "left join {1}.fpc_routepart t1 on t.RoutePartID=t1.ID " +
                            "left join {1}.fpc_routepartpoint t2 on t.RoutePartPointID=t2.ID " +
                            "left join {0}.oms_order t3 on t.OrderID=t3.ID " +
                            "left join {0}.aps_task_part t4 on t.TaskPartID=t4.ID " +
                            "left join {0}.aps_task_partpoint t5 on t.TaskPartPointID=t5.ID " +
                            "where t.Active=1 and t.StationDate<=:StationDate and t4.Status in (2,4) "
                            + "and ( :wOrderID <= 0 or t.OrderID=:wOrderID) "
                            + "and ( :wRoutePartName = '''' or t1.Name like ''%{2}%'') "
                            + "and ( :wRoutePartPointName = '''' or t2.Name like ''%{3}%'') "
                            + "",
                    DBSchemas.APS.getDBName(), DBSchemas.PDM.getDBName(), wRoutePartName, wRoutePartPointName);

            Map<String, Object> wParamMap = new HashMap<String, Object>();

            wParamMap.put("StationDate", wDate);
            wParamMap.put("wOrderID", wOrderID);
            wParamMap.put("wRoutePartName", wRoutePartName);
            wParamMap.put("wRoutePartPointName", wRoutePartPointName);

            wSQL = this.DMLChange(wSQL);

            List<Map<String, Object>> wQueryResult = this.queryForList(wSQL, wParamMap, wPagination);

            APSTaskPartPointDayParent wItem;
            for (Map<String, Object> wReader : wQueryResult) {
                wItem = new APSTaskPartPointDayParent();

                wItem.OrderID = StringUtils.parseInt(wReader.get("OrderID"));
                wItem.OrderNo = StringUtils.parseString(wReader.get("OrderNo"));
                wItem.RoutePartID = StringUtils.parseInt(wReader.get("RoutePartID"));
                wItem.RoutePartName = StringUtils.parseString(wReader.get("RoutePartName"));
                wItem.RoutePartOrder = StringUtils.parseInt(wReader.get("RoutePartOrder"));
                wItem.RoutePartPointID = StringUtils.parseInt(wReader.get("RoutePartPointID"));
                wItem.RoutePartPointName = StringUtils.parseString(wReader.get("RoutePartPointName"));
                wItem.RoutePartPointOrder = StringUtils.parseInt(wReader.get("RoutePartPointOrder"));
                wItem.TaskPartID = StringUtils.parseInt(wReader.get("TaskPartID"));
                wItem.TaskPartStatus = StringUtils.parseInt(wReader.get("TaskPartStatus"));
                wItem.TaskPartPointID = StringUtils.parseInt(wReader.get("TaskPartPointID"));
                wItem.PlanNum = StringUtils.parseFloat(wReader.get("PlanNum"));
                wItem.FinishedNum = StringUtils.parseFloat(wReader.get("ActNum"));

                wResult.add(wItem);
            }
        } catch (Exception ex) {
            logger.error("APS_QueryDayPlanParent", ex);
            wErrorCode.Result = ExceptionTypes.DBSQL.getValue();
        }
        return wResult;
    }

    public Map<Integer, Float> APS_QueryPlanedMap(List<Integer> wTaskPartPointIDList,
                                                  OutResult<Integer> wErrorCode) {
        Map<Integer, Float> wResult = new HashMap<>();
        try {
            if (wTaskPartPointIDList == null || wTaskPartPointIDList.size() == 0) {
                return wResult;
            }

            String wSQL = StringUtils.Format("select TaskPartPointID,sum(PlantNum) FQTY from {0}" +
                            ".aps_task_partpoint_day " +
                            "where TaskPartPointID in ({1}) and Status>=2 group by TaskPartPointID ",
                    DBSchemas.APS.getDBName(), StringUtils.Join(",", wTaskPartPointIDList));

            Map<String, Object> wParamMap = new HashMap<String, Object>();

            wSQL = this.DMLChange(wSQL);

            List<Map<String, Object>> wQueryResult = this.queryForList(wSQL, wParamMap);

            for (Map<String, Object> wReader : wQueryResult) {
                int wTaskPartPointID = StringUtils.parseInt(wReader.get("TaskPartPointID"));
                float wFQTY = StringUtils.parseFloat(wReader.get("FQTY"));

                wResult.put(wTaskPartPointID, wFQTY);
            }
        } catch (Exception ex) {
            logger.error("APS_QueryPlanedMap", ex);
            wErrorCode.Result = ExceptionTypes.DBSQL.getValue();
        }
        return wResult;
    }

    public List<APSTaskPartPointDayParent> APS_QueryDispatchList(int wOrderID,
                                                                 String wRoutePartName, String wRoutePartPointName,
                                                                 Pagination wPagination,
                                                                 OutResult<Integer> wErrorCode) {
        List<APSTaskPartPointDayParent> wResult = new ArrayList<APSTaskPartPointDayParent>();
        try {
            String wSQL = StringUtils.Format("SELECT distinct t.OrderID,t3.Code OrderNo,t.RoutePartID,t" +
                            ".RoutePartPointID,t1.Name " +
                            "RoutePartName,t2.Name RoutePartPointName,t.TaskPartID,t4.Status TaskPartStatus,t" +
                            ".TaskPartPointID,t5.PlanNum " +
                            "FROM {0}.aps_task_partpoint_day t " +
                            "left join {1}.fpc_routepart t1 on t.RoutePartID=t1.ID " +
                            "left join {1}.fpc_routepartpoint t2 on t.RoutePartPointID=t2.ID " +
                            "left join {0}.oms_order t3 on t.OrderID=t3.ID " +
                            "left join {0}.aps_task_part t4 on t.TaskPartID=t4.ID " +
                            "left join {0}.aps_task_partpoint t5 on t.TaskPartPointID=t5.ID " +
                            "where t4.Status=2 and t.Status=2 "
                            + "and ( :wOrderID <= 0 or t.OrderID=:wOrderID) "
                            + "and ( :wRoutePartName = '''' or t1.Name like ''%{2}%'') "
                            + "and ( :wRoutePartPointName = '''' or t2.Name like ''%{3}%'') "
                            + "",
                    DBSchemas.APS.getDBName(), DBSchemas.PDM.getDBName(), wRoutePartName, wRoutePartPointName);

            Map<String, Object> wParamMap = new HashMap<String, Object>();

            wParamMap.put("wOrderID", wOrderID);
            wParamMap.put("wRoutePartName", wRoutePartName);
            wParamMap.put("wRoutePartPointName", wRoutePartPointName);

            wSQL = this.DMLChange(wSQL);

            List<Map<String, Object>> wQueryResult = this.queryForList(wSQL, wParamMap, wPagination);

            APSTaskPartPointDayParent wItem;
            for (Map<String, Object> wReader : wQueryResult) {
                wItem = new APSTaskPartPointDayParent();

                wItem.OrderID = StringUtils.parseInt(wReader.get("OrderID"));
                wItem.OrderNo = StringUtils.parseString(wReader.get("OrderNo"));
                wItem.RoutePartID = StringUtils.parseInt(wReader.get("RoutePartID"));
                wItem.RoutePartName = StringUtils.parseString(wReader.get("RoutePartName"));
                wItem.RoutePartPointID = StringUtils.parseInt(wReader.get("RoutePartPointID"));
                wItem.RoutePartPointName = StringUtils.parseString(wReader.get("RoutePartPointName"));
                wItem.TaskPartID = StringUtils.parseInt(wReader.get("TaskPartID"));
                wItem.TaskPartStatus = StringUtils.parseInt(wReader.get("TaskPartStatus"));
                wItem.TaskPartPointID = StringUtils.parseInt(wReader.get("TaskPartPointID"));
                wItem.PlanNum = StringUtils.parseInt(wReader.get("PlanNum"));

                wResult.add(wItem);
            }
        } catch (Exception ex) {
            logger.error("APS_QueryDispatchList", ex);
            wErrorCode.Result = ExceptionTypes.DBSQL.getValue();
        }
        return wResult;
    }

    /**
     *查询出哪些工序需要首检
     */
    public Map<Integer, Boolean> APS_GetFirstCheckStatusMap(BMSEmployee wLoginUser,
                                                            List<Integer> wRoutePartPointIDList,
                                                            OutResult<Integer> wErrorCode) {
        Map<Integer, Boolean> wResult = new HashMap<>();
        try {
            if (wRoutePartPointIDList == null || wRoutePartPointIDList.size() <= 0) {
                return wResult;
            }

            String wSQL = StringUtils.Format("SELECT DISTINCT RoutePartPointID FROM {0}.`fpc_route_step` " +
                            "WHERE RoutePartPointID IN ({1}) AND IsFirstCheck=1 AND Active=1;",
                    DBSchemas.PDM.getDBName(), StringUtils.Join(",", wRoutePartPointIDList));

            Map<String, Object> wParamMap = new HashMap<String, Object>();

            wSQL = this.DMLChange(wSQL);

            List<Map<String, Object>> wQueryResult = this.queryForList(wSQL, wParamMap);

            for (Map<String, Object> wReader : wQueryResult) {
                int wRoutePartPointID = StringUtils.parseInt(wReader.get("RoutePartPointID"));
                wResult.put(wRoutePartPointID, true);
            }
        } catch (Exception ex) {
            logger.error(ex.toString());
        }
        return wResult;
    }
}
